home *** CD-ROM | disk | FTP | other *** search
- /*
- * fontfilt.c - cawf post-processing font filter
- *
- * V. Abell
- * Purdue University Computing Center
- *
- * Fontfilt filters output from cawf, the C version of Henry Spencer's
- * Amazingly Workable (text) Formatter, awf, to produce printer-specific
- * codes for bold and italic characters. (Cawf provides modest support
- * for documents formatted with nroff's man(7) and ms(7) macros.)
- *
- * Fontfilt is based on work by and suggestions from Chet Creider
- * <creider@csd.uwo.ca>.
- */
-
-
- /*
- * Copyright (c) 1991 Purdue University Research Foundation,
- * West Lafayette, Indiana 47907. All rights reserved.
- *
- * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
- * University Computing Center. Not derived from licensed software;
- * derived from work by Chet Creider <creider@csd.uwo.ca>.
- *
- * Permission is granted to anyone to use this software for any
- * purpose on any computer system, and to alter it and redistribute
- * it freely, subject to the following restrictions:
- *
- * 1. The author is not responsible for any consequences of use of
- * this software, even if they arise from flaws in it.
- *
- * 2. The origin of this software must not be misrepresented, either
- * by explicit claim or by omission. Credits must appear in the
- * documentation.
- *
- * 3. Altered versions must be plainly marked as such, and must not
- * be misrepresented as being the original software. Credits must
- * appear in the documentation.
- *
- * 4. This notice may not be removed or altered.
- */
-
-
- /*
- * Usage:
- *
- * fontfilt [-c config] [-d device] [-f font] [file(s)]
- *
- * where:
- *
- * -c config specifies an alternate configuration file
- * (default directory = CAWFLIB definition or
- * CAWFLIB env. variable)
- *
- * -d device specifies the output device
- *
- * -f font specifies the font to be used on the
- * output device
- *
- * file(s) the path(s) to the file(s) containing cawf,
- * -fe format output
- *
- * Cawf's font ESCape mode must be used - e. g.,
- *
- * % cawf -fe -man cawf.1 | fontfilt -dlj3 -flg12
- */
-
-
- /*
- * See fontfilt.cf for a list of supported devices and fonts, or use
- * the -h (help) option. The default device is the last device named
- * in fontfilt.cf.
- */
-
- #include <stdio.h>
- #ifdef STDLIB
- #include <stdlib.h>
- #endif
- #ifdef UNIX
- #ifdef USG
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #else
- #include <string.h>
- #endif
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #include "cawflib.h"
-
-
- /*
- * Local definitions
- */
-
- #define BOLD 'B'
- #define CONFIG "fontfilt.cf"
- #define ESC 0x1b
- #define ITALIC 'I'
- #define MAXLINE 512
- #define ROMAN 'R'
-
-
- /*
- * Local global variables
- */
-
- static char *Besc = NULL; /* bold font escape string pointer */
- static char *Conf = NULL; /* configuration file path */
- static char *Defdev = NULL; /* default device name (last name of
- * fontfilt.cf */
- static char Font = ROMAN; /* current font */
- static char *Iesc = NULL; /* italic font escape string pointer */
- static char *Pname; /* program name */
- static char *Resc = NULL; /* roman font escape string pointer */
-
-
- /*
- * Structure for font definitions
- */
-
- struct font {
- char *nm; /* font name */
- char *fi; /* font initialization character sequence */
- struct font *next; /* next font fot this device */
- };
-
-
- /*
- * Device structure
- */
-
- struct dev {
- char *nm; /* device name */
- struct font *f; /* supported fonts */
- char *b; /* bold font ESCape sequence */
- char *i; /* italic font ESCape sequence */
- char *r; /* Roman font ESCape sequence */
- struct dev *next; /* next device */
- } *Dp = NULL;
-
-
- /*
- * Externals
- */
-
- extern char *optarg; /* getopt(3) argument pointer */
- extern int optind; /* getopt(3) index */
-
-
- /*
- * Function definitions
- */
-
- static char *Convstr();
- static int Convfont(), Readcf();
- static void Bold(), Getec(), Italic(), Roman();
-
- #ifndef STDLIB
- char *getenv(), *malloc(), *strchr(), *strrchr();
- #endif
-
-
- /*
- * Main program
- */
-
- main(argc, argv)
- int argc; /* argument count */
- char *argv[]; /* argument pointers */
- {
- register int c; /* character buffer */
- char *cnm = NULL; /* config file name */
- char *dnm = NULL; /* device name */
- struct dev *dp; /* device */
- char *fnm = NULL; /* font name */
- int err = 0; /* argument error count */
- int fc, fx; /* file count and index */
- struct font *fp; /* font pointer */
- FILE *fs; /* file stream */
- int help = 0; /* -h status */
- struct stat sbuf; /* file stat() buffer */
- char *sep; /* separator pointer */
- /*
- * Save program name.
- */
- if ((Pname = strrchr(argv[0], '\\')) != NULL)
- Pname++;
- else if ((Pname = strrchr(argv[0], '/')) != NULL)
- Pname++;
- else
- Pname = argv[0];
- /*
- * Process options.
- */
- while ((c = getopt(argc, argv, "c:d:f:h")) != EOF) {
- switch (c) {
- /*
- * -c config -- specify configuration file
- */
- case 'c':
- if (cnm != NULL) {
- (void) fprintf(stderr,
- "%s: duplicate config name\n", Pname);
- err = 1;
- } else
- cnm = optarg;
- break;
- /*
- * -d device -- specify device
- */
- case 'd':
- if (dnm != NULL) {
- (void) fprintf(stderr,
- "%s: duplicate device name\n", Pname);
- err = 1;
- } else
- dnm = optarg;
- break;
- /*
- * -f font -- specify font
- */
- case 'f':
- if (fnm != NULL) {
- (void) fprintf(stderr,
- "%s: duplicate font name\n", Pname);
- err = 1;
- } else
- fnm = optarg;
- break;
- /*
- * -h -- request help
- */
- case 'h':
- help++;
- break;
- /*
- * unknown option
- */
- case '?':
- err = 1;
- }
- }
- /*
- * Handle file arguments.
- */
- if (optind >= argc)
- fc = 0;
- else {
- fc = argc;
- for (fx = optind; fx < fc; fx++) {
- if (stat(argv[fx], &sbuf) != 0) {
- (void) fprintf(stderr, "%s: can't find %s\n",
- Pname, argv[fx]);
- err++;
- }
- }
- }
- /*
- * Read configuration file.
- */
- if (Readcf(cnm) == 0)
- err++;
- /*
- * Validate device name.
- */
- if (dnm == NULL)
- dnm = Defdev;
- for (dp = Dp; dp; dp = dp->next) {
- if (strcmp(dnm, dp->nm) == 0)
- break;
- }
- if (dp) {
- if (fnm == NULL && dp->f)
- fnm = (dp->f)->nm;
- } else {
- if (dnm == NULL)
- (void) fprintf(stderr, "%s: no device specified\n",
- Pname);
- else
- (void) fprintf(stderr, "%s: unknown device: %s\n",
- Pname, dnm);
- err++;
- dp = NULL;
- }
- /*
- * Validate font name.
- */
- if (fnm != NULL && dp) {
- for (fp = dp->f; fp; fp = fp->next) {
- if (strcmp(fnm, fp->nm) == 0)
- break;
- }
- if (fp == NULL) {
- (void) fprintf(stderr,
- "%s: font %s not defined for device %s\n",
- Pname, fnm, dnm);
- err++;
- }
- } else
- fp = NULL;
- /*
- * Go no further if errors have been detected, or help has been requested.
- */
- if (err || help) {
- (void) fprintf(stderr,
- "%s usage: [-c config ] [-d device]", Pname);
- (void) fprintf(stderr,
- " [-f font] [file(s)]\n");
- (void) fprintf(stderr,
- "\t-c config specify configuration file path\n");
- if (Conf != NULL) {
- (void) fprintf(stderr,
- "\t (currently using %s)\n", Conf);
- }
- (void) fprintf(stderr,
- "\t-d device specify device name\n");
- if (Defdev != NULL) {
- (void) fprintf(stderr,
- "\t (default = %s)\n", Defdev);
- }
- (void) fprintf(stderr,
- "\t-f font specify font name\n");
- (void) fprintf(stderr,
- "\tfile(s) specify cawf -fe output files\n");
- (void) fprintf(stderr,
- "\t (default = standard input)\n");
- (void) fprintf(stderr,
- "-d -f (first font is default)\n");
- for (dp = Dp; dp; dp = dp->next) {
- (void) fprintf(stderr, "%-8.8s ", dp->nm);
- if ((fp = dp->f) == NULL)
- (void) fprintf(stderr, "none\n");
- else {
- sep = "";
- while (fp) {
- (void) fprintf(stderr,
- "%s%s", sep, fp->nm);
- sep = "|";
- fp = fp->next;
- }
- (void) putc('\n', stderr);
- }
- }
- if (err)
- exit(1);
- exit(0);
- }
- /*
- * Issue font selection, if any, and set up font escape string pointers.
- */
- if (fp && fp->fi)
- fputs(fp->fi, stdout);
- Besc = dp->b;
- Iesc = dp->i;
- Resc = dp->r;
- /*
- * Loop through the input files.
- */
- fx = optind;
- do {
-
- /*
- * If there are no files, use standard input (once).
- */
- if (fc == 0)
- fs = stdin;
- else {
- /*
- * Open the named file.
- */
- #ifdef UNIX
- if ((fs = fopen(argv[fx], "r")) == NULL)
- #else
- if ((fs = fopen(argv[fx], "rt")) == NULL)
- #endif
- {
- (void) fprintf(stderr, "%s: can't open %s\n",
- Pname, argv[fx]);
- exit(1);
- }
- }
- /*
- * Read and process the file.
- */
- while ( ! feof(fs) && (c = getc(fs)) != EOF) {
- switch (c) {
-
- case ESC:
- Getec(fs);
- if ( ! feof(fs) && (c = getc(fs)) != EOF)
- putchar(c);
- break;
- default:
- Roman();
- putchar(c);
- break;
- }
- }
- if (fc != 0)
- (void) fclose(fs);
- } while (++fx < fc);
- exit(0);
- }
-
-
- /*
- * Bold() - set bold font
- */
-
- static void
- Bold()
-
- {
- if (Font == BOLD)
- return;
- if (Besc)
- fputs(Besc, stdout);
- Font = BOLD;
- }
-
-
- /*
- * Convfont(dp, s) - convert a font for a device
- *
- * entry:
- * dp = device structure pointer
- * s = font definition string -- "name=initialization"
- *
- * exit:
- * return = 0 if errors detected
- */
-
- static int
- Convfont(dp, s)
- struct dev *dp; /* device structure pointer */
- char *s; /* font definition string */
- {
- char *cp; /* temporary character pointer */
- char *fn; /* font name */
- struct font *fp; /* font structure pointer */
- struct font *tfp; /* temporary font structure pointer */
- /*
- * Get the font name allocate space for it and allocate space for
- * a font structure.
- */
- if ((cp = strchr(s, '=')) == NULL) {
- (void) fprintf(stderr, "%s: bad %s font line format: %s\n",
- Pname, dp->nm, s);
- return(0);
- }
- if ((fn = malloc(cp - s + 1)) == NULL) {
- (void) fprintf(stderr, "%s: no space for %s font name %s\n",
- Pname, dp->nm, s);
- return(0);
- }
- (void) strncpy(fn, s, cp - s);
- fn[cp - s] = '\0';
- if ((fp = (struct font *)malloc(sizeof(struct font))) == NULL) {
- (void) fprintf(stderr, "%s: no space for %s font struct %s\n",
- Pname, dp->nm, fn);
- return(0);
- }
- /*
- * Fill in the font structure with the font name and the initialization
- * string.
- */
- fp->nm = fn;
- fp->next = NULL;
- if (dp->f == NULL)
- dp->f = fp;
- else {
- for (tfp = dp->f; tfp; tfp = tfp->next) {
- if (tfp->next == NULL) {
- tfp->next = fp;
- break;
-
- }
- }
- }
- if ((fp->fi = Convstr(cp + 1)) == NULL)
- return(0);
- return(1);
- }
-
-
- /*
- * Convstr(s) - convert a string
- *
- * entry:
- * s = input string
- *
- * exit:
- * return = converted string address
- * NULL = error
- */
-
- static char *
- Convstr(s)
- char *s; /* input string */
- {
- int c; /* character assembly */
- char *cp; /* temporary character pointer */
- char *em; /* error message */
- int i; /* temporary index */
- int l; /* length */
- char *r; /* result string */
- /*
- * Make space for the result.
- */
- if ((r = malloc(strlen(s) + 1)) == NULL) {
- (void) fprintf(stderr, "%s: out of string space at %s\n",
- Pname, r);
- return(NULL);
- }
- /*
- * Copy the input string to the result, processing '\\' escapes.
- */
- for (cp = r; *s;) {
- switch (*s) {
-
- case '\\':
- s++;
- if (*s >= '0' && *s <= '7') {
- /*
- * '\xxx' -- octal form
- */
- for (c = i = 0; i < 3; i++, s++) {
- if (*s < '0' || *s > '7') {
- em = "non-octal char";
- bad_string:
- (void) fprintf(stderr,
- "%s: %s : %s\n",
- Pname, em, r);
- return(NULL);
- }
- c = (c << 3) + *s - '0';
- }
- if (c > 0377) {
- em = "octal char > 0377";
- goto bad_string;
- }
- *cp++ = c;
- } else if (*s == 'x') {
- /*
- * '\xyy' -- hexadecimal form
- */
- s++;
- for (c = i = 0; i < 2; i++, s++) {
- if ( ! isascii(*s) && ! isalpha(*s)
- && ! isdigit(*s)) {
- non_hex_char:
- em = "non-hex char";
- goto bad_string;
- }
- c = c << 4;
- if (*s >= '0' && *s <= '9')
- c += *s - '0';
- else if ((*s >= 'a' && *s <= 'f')
- || (*s >= 'A' && *s <= 'F'))
- c += *s + 10 -
- (isupper(*s) ? 'A' : 'a');
- else
- goto non_hex_char;
- }
- *cp++ = c;
- } else if (*s == 'E' || *s == 'e') {
- /*
- * '\E' or '\e' -- ESCape
- */
- *cp++ = ESC;
- } else if (*s == '\0') {
- em = "no char after \\";
- goto bad_string;
- } else
- /*
- * escaped character (for some reason)
- */
- *cp++ = *s++;
- break;
- /*
- * Copy a "normal" character.
- */
- default:
- *cp++ = *s++;
- }
- }
- *cp = '\0';
- return(r);
- }
-
-
- /*
- * Getec(fs) - get ESCape follower character
- *
- * entry:
- * fs = file stream
- */
-
- static void
- Getec(fs)
- FILE *fs; /* file stream */
- {
- register int c;
-
- if (feof(fs) || (c = getc(fs)) == EOF)
- return;
- switch (c) {
-
- case ROMAN:
- Roman();
- break;
- case ITALIC:
- Italic();
- break;
- case BOLD:
- Bold();
- break;
- default:
- (void) fprintf (stderr,
- "%s: unknown escape sequence ESC-0x%x\n",
- Pname, c);
- break;
- }
- }
-
-
- /*
- * Italic() - set italic font
- */
-
- static void
- Italic()
-
- {
- if (Font == ITALIC)
- return;
- if (Iesc)
- fputs(Iesc, stdout);
- Font = ITALIC;
- }
-
-
- /*
- * Roman() - set Roman font
- */
-
- static void
- Roman()
-
- {
- if (Font == ROMAN)
- return;
- if (Resc)
- fputs(Resc, stdout);
- Font = ROMAN;
- }
-
-
- /*
- * Readcf(p) - read configuration file
- *
- * entry:
- * p = configuration file path
- *
- * exit:
- * return = 0 if error detected
- */
-
- static int
- Readcf(p)
- char *p; /* configuration file path */
- {
- FILE *fs; /* file stream */
- char *dn; /* device name */
- struct dev *dp; /* device structure pointer */
- int err = 0; /* errror count */
- int l; /* length */
- char line[MAXLINE]; /* line buffer */
- char *s; /* temporary string pointer */
- /*
- * If a path is supplied, use it.
- */
- if (p)
- Conf = p;
- else {
-
- /*
- * Use the CAWFLIB environment if it is defined.
- */
- if ((Conf = getenv("CAWFLIB")) == NULL)
- Conf = CAWFLIB;
- l = strlen(Conf) + 1 + strlen(p ? p : CONFIG) + 1;
- if ((s = malloc(l)) == NULL) {
- (void) fprintf(stderr, "%s: no space for %s name\n",
- Pname,
- p ? p : CONFIG);
- return(0);
- }
- (void) sprintf(s, "%s/%s", Conf, p ? p : CONFIG);
- Conf = s;
- }
- /*
- * Open the configuration file.
- */
- #ifdef UNIX
- if ((fs = fopen(Conf, "r")) == NULL)
- #else
- if ((fs = fopen(Conf, "rt")) == NULL)
- #endif
- {
- (void) fprintf(stderr, "%s: can't open config file: %s\n",
- Pname, Conf);
- return(0);
- }
- *line = ' ';
- /*
- * Look for a device definition line -- a line that begins with a name.
- */
- while ( ! feof(fs)) {
- if (isascii(*line) && (isspace(*line) || *line == '#')) {
- (void) fgets(line, MAXLINE, fs);
- continue;
- }
- if ((s = strrchr(line, '\n')) != NULL)
- *s = '\0';
- else
- line[MAXLINE-1] = '\0';
- /*
- * Allocate space for the name and the device structure.
- */
- if ((dn = malloc(strlen(line) + 1)) == NULL) {
- (void) fprintf(stderr,
- "%s: no string space for device %s\n",
- Pname, line);
- return(0);
- }
- (void) strcpy(dn, line);
- if ((dp = (struct dev *)malloc(sizeof(struct dev))) == NULL) {
- (void) fprintf(stderr,
- "%s: no space for structure for device %s\n",
- Pname, dn);
- return(0);
- }
- dp->next = Dp;
- Dp = dp;
- Defdev = dp->nm = dn;
- dp->b = dp->i = dp->r = NULL;
- dp->f = NULL;
- /*
- * Read the parameter lines for the device.
- */
- while (fgets(line, MAXLINE, fs) != NULL) {
- if ( ! isascii(*line) || *line != '\t')
- break;
- if ( ! isascii(line[1]) || ! isalpha(line[1])
- || line[2] != '=')
- break;
- if ((s = strrchr(line, '\n')) != NULL)
- *s = '\0';
- else
- line[MAXLINE-1] = '\0';
- switch (line[1]) {
- /*
- * \tb=<bolding_string>
- */
- case 'b':
- if ((dp->b = Convstr(&line[3])) == NULL)
- err++;
- break;
- /*
- * \ti=<italicization_string>
- */
- case 'i':
- if ((dp->i = Convstr(&line[3])) == NULL)
- err++;
- break;
- /*
- * \tr=<return_to_Roman_string>
- */
- case 'r':
- if ((dp->r = Convstr(&line[3])) == NULL)
- err++;
- break;
- /*
- * \tf=<font_name>=<font_initialization_string>
- */
- case 'f':
- if (Convfont(dp, &line[3]) == 0)
- err++;
- break;
- /*
- * ????
- */
- default:
- (void) fprintf(stderr,
- "%s: unknown device %s line %s\n",
- Pname, dp->nm, line);
- err++;
- }
- }
- }
- (void) fclose(fs);
- if (err)
- return(0);
- return(1);
- }
-